'use strict'

//切换到程序当前文件所在目录
process.chdir(__dirname)

const Titbit = require('titbit')
const TitbitToken = require('titbit-token')
const accessToken = require('./lib/accessToken')
const getOpenID = require('./lib/getOpenID')

const app = new Titbit({
  //启用调试模式
  debug: true,
  //默认捕获开发者没有明确处理的异常
  //strong: true
})

//初始化token加解密扩展
let tok = new TitbitToken({
  //3小时有效
  expires: 10800_000,
  //用于加解密的密钥(密码)
  key: '1234567890qazwer',
})

//中间件演示
app.use(async (ctx, next) => {
  //检测是否提交了token
  if (!ctx.headers.authorization) {
    //401状态码表示的是没有登录或者token值已经超时
    return ctx.status(401).send('未登录,请登录验证')
  }

  let vk = tok.verifyAccessToken(ctx.headers.authorization)

  if (!vk.ok) {
    //非法的token值，code表示错误的状态码，是一个字符串。
    return ctx.status(401).send(vk.code)
  }

  //验证通过，解密后的数据在data里面
  //把data赋值给ctx.box.user，后续函数可以获取
  ctx.box.user = vk.data

  await next()
}, {method: ['POST', 'PUT', 'DELETE']})

app.use(async (ctx, next) => {
  console.log(ctx.method, ctx.path, '中间件2')
  await next()
  console.log('中间件2 end')
})

/**
 * 处理小程序登录：
 *   - 使用appid和secret + code获取用户的openid
 *   - 成功之后，对信息进行加密，返回加密的数据即为token值（登录凭证）
 */
app.get('/mp-login/:code', async ctx => {
  //路由参数 code 放在ctx.param中
  let tk = await getOpenID(ctx.param.code)
  if (!tk.ok) {
    return ctx.status(400).send('请求遇到网络错误')
  }
  //把返回值转成object
  let info = tk.json()
  
  //获取失败，返回400状态码，并返回错误信息
  if (!info.openid || info.errcode) {
    return ctx.status(400).send(info.errmsg)
  }

  //return ctx.send(info)
  //加密处理返回token值
  let data = {
    //每次登录都有一个随机值，保证生成的token不一致
    rand: Math.random(),
    openid: info.openid,
  }

  ctx.send( tok.makeAccessToken(data) )
}, {name: '登录', group: 'login'})

//上传图片的目录
let imagePath = './images'

//添加上传图片路由，post请求，路径是 /image
app.post('/image', async ctx => {
  //获取文件对象，上传名是image
  let imgfile = ctx.getFile('image')
  if (!imgfile) {
    //如果没有文件，返回400状态码
    return ctx.status(400).send('没有图片文件')
  }
  /*imgfile是一个object，属性值：
      filename、content-type、start、end
  */
  //ctx.helper是一个object，提供了一些助手函数
  //makeName是生成一个唯一文件名。
  let upload_name = ctx.helper.makeName(imgfile.filename)

  //moveFile是把上传的文件放在磁盘的某个位置
  await ctx.moveFile(imgfile, `${imagePath}/${upload_name}`)

  ctx.send({upload_name})
})

//返回对应的图片数据，:name是参数，
// /image/:name是带参数的路由
app.get('/image/:name', async ctx => {
  try {
    //路由参数都放在ctx.param中
    let imgfile = `${imagePath}/${ctx.param.name}`
    //ctx.reply是响应对象，在HTTP/1.1是response实例
    await ctx.helper.pipe(imgfile, ctx.reply)
  } catch (err) {
    return ctx.status(404).send('image not found')
  }
})

app.run(1234)
